package com.pdool.room.mgr;

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.google.protobuf.GeneratedMessageV3;
import com.pdool.common.dto.room.CreateRoomInfo;
import com.pdool.common.service.game.IGameService;
import com.pdool.room.akka.SpringExtProvider;
import com.pdool.room.akka.TickActor;
import com.pdool.room.context.RoomContext;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 房间管理器
 */
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Data
@Slf4j
public class RoomMgr implements InitializingBean, ApplicationRunner {
    private static RoomMgr instance;

    public static RoomMgr getInstance() {
        return instance;
    }

    @Override
    public void afterPropertiesSet() {
        instance = this;
    }

    @Autowired
    private ActorSystem actorSystem;

    @DubboReference(url = "${game.dubbo}")
    IGameService gameService;
    Long checkTime;


    public Map<String, ActorRef> roomMap = new HashMap<>();
    public Map<String, Long> createRoomTimeMap = new HashMap<>();

    public String createRoom(CreateRoomInfo createRoomInfo) {
        String roomId = IdUtil.getSnowflakeNextIdStr();
        ActorRef ref = actorSystem.actorOf(SpringExtProvider.getInstance().get(actorSystem).create("roomActor"), roomId);
        createRoomInfo.setRoomId(roomId);
        ref.tell(createRoomInfo, ActorRef.noSender());
        roomMap.put(roomId, ref);
        createRoomTimeMap.put(roomId, System.currentTimeMillis());
        log.error("当前房间数： {}", roomMap.size());
        return roomId;
    }

    public void sendMsg2Room(String roomId, Object msg) {
        ActorRef actorRef = roomMap.get(roomId);
        if (actorRef == null) {
            log.error(" roomId  {}  is  not exist ", roomId);
            log.error("", ExceptionUtil.getRootStackElement());
            return;
        }
        actorRef.tell(msg, ActorRef.noSender());
    }

    public void sendMsg2Client(long roleId, int msgId, GeneratedMessageV3 msg) {
        byte[] build = msg.toByteArray();
        ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES + build.length);
        buffer.putInt(msgId);
        buffer.put(build);
        gameService.trans2Client(roleId, buffer.array());
    }


    public void sendMsg2Room(RoomContext roomContext, int msgId, GeneratedMessageV3 msg) {
        byte[] build = msg.toByteArray();
        ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES + build.length);
        buffer.putInt(msgId);
        buffer.put(build);
        byte[] array = buffer.array();
        for (Long roleId : roomContext.getMemberMap().keySet()) {
            gameService.trans2Client(roleId, array);
        }
    }


    public void stopActor(String roomId) {
        ActorRef actorRef = roomMap.get(roomId);
        if (actorRef != null) {
            SpringUtil.getBean(ActorSystem.class).stop(actorRef);
            roomMap.remove(roomId);
            createRoomTimeMap.remove(roomId);
        }

    }

    @Override
    public void run(ApplicationArguments args) {
        //  启动定时器
        ActorRef actorRef = actorSystem.actorOf(Props.create(TickActor.class));
        actorRef.tell("init", ActorRef.noSender());
    }

    public void checkRoom() {
        long now = System.currentTimeMillis();
        //  1小时检测一次
        if (checkTime != null && now - checkTime < 60 * 60 * 1000) {
            return;
        }
        try {
            List<String> roomList = new ArrayList<>(createRoomTimeMap.keySet());
            int count = 0;
            for (String roomId : roomList) {
                Long createTime = createRoomTimeMap.get(roomId);
                if (createTime == null) {
                    continue;
                }
                //  超过30分钟的全部杀死
                if (now - createTime >= 30 * 60 * 1000) {
                    stopActor(roomId);
                    count++;
                }
            }
            checkTime = now;
            log.warn("check finish del count-->{} ", count);
        } catch (Exception e) {
            log.error("", e);
        }
    }

}
